package com.ollobot.authorization.config;

import com.ollobot.authorization.security.EmailVerificationAuthenticationProvider;
import com.ollobot.authorization.service.CustomOAuth2UserService;
import com.ollobot.authorization.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;

import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurityConfig {

    private final UserService userService;
    private final CustomOAuth2UserService customOAuth2UserService;
    private final EmailVerificationAuthenticationProvider emailVerificationAuthenticationProvider;
    private final PasswordEncoder passwordEncoder;

    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // 前后端分离禁用CSRF
            .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 配置CORS
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话
            )
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/api/auth/**", "/oauth2/**", "/login/oauth2/**", "/.well-known/**").permitAll()
                .requestMatchers("/actuator/**").permitAll() // 监控端点
                .anyRequest().authenticated()
            )
            .exceptionHandling(exceptions -> exceptions
                .authenticationEntryPoint(authenticationEntryPoint()) // 自定义认证入口点
                .accessDeniedHandler(accessDeniedHandler()) // 自定义访问拒绝处理器
            )
            .oauth2Login(oauth2 -> oauth2
                .userInfoEndpoint(userInfo -> userInfo
                    .userService(customOAuth2UserService)
                )
                .successHandler((request, response, authentication) -> {
                    // 前后端分离，返回JSON响应
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write("{\"success\":true,\"message\":\"Login successful\",\"redirectUrl\":\"/dashboard\"}");
                })
                .failureHandler((request, response, exception) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    response.setStatus(401);
                    response.getWriter().write("{\"success\":false,\"message\":\"Login failed: " + exception.getMessage() + "\"}");
                })
            )
            .logout(logout -> logout
                .logoutSuccessHandler((request, response, authentication) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write("{\"success\":true,\"message\":\"Logout successful\"}");
                })
                .permitAll()
            );

        return http.build();
    }

    @Bean
    public org.springframework.web.cors.CorsConfigurationSource corsConfigurationSource() {
        org.springframework.web.cors.CorsConfiguration configuration = new org.springframework.web.cors.CorsConfiguration();
        configuration.setAllowedOriginPatterns(java.util.Arrays.asList("*")); // 允许所有域名，生产环境应该限制
        configuration.setAllowedMethods(java.util.Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(java.util.Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        
        org.springframework.web.cors.UrlBasedCorsConfigurationSource source = new org.springframework.web.cors.UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }


    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
        daoProvider.setUserDetailsService(userService);
        daoProvider.setPasswordEncoder(passwordEncoder);

        return new ProviderManager(Arrays.asList(
            daoProvider,
            emailVerificationAuthenticationProvider
        ));
    }

    /**
     * 自定义认证入口点 - 当用户未认证时返回JSON响应而不是重定向到登录页面
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            
            String errorMessage = "未认证，请先登录";
            if (authException != null && authException.getMessage() != null) {
                errorMessage = authException.getMessage();
            }
            
            String jsonResponse = String.format(
                "{\"success\":false,\"code\":401,\"message\":\"%s\",\"timestamp\":%d}",
                errorMessage,
                System.currentTimeMillis()
            );
            
            try {
                response.getWriter().write(jsonResponse);
            } catch (IOException e) {
                throw new RuntimeException("Failed to write authentication error response", e);
            }
        };
    }

    /**
     * 自定义访问拒绝处理器 - 当用户权限不足时返回JSON响应
     */
    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            
            String errorMessage = "权限不足，拒绝访问";
            if (accessDeniedException != null && accessDeniedException.getMessage() != null) {
                errorMessage = accessDeniedException.getMessage();
            }
            
            String jsonResponse = String.format(
                "{\"success\":false,\"code\":403,\"message\":\"%s\",\"timestamp\":%d}",
                errorMessage,
                System.currentTimeMillis()
            );
            
            try {
                response.getWriter().write(jsonResponse);
            } catch (IOException e) {
                throw new RuntimeException("Failed to write access denied error response", e);
            }
        };
    }
}
